# eccezione usata dalla classe Magazzino per segnalare
# che un articolo non e' disponibile
class ArtNonDispException < Exception
end

class Articolo
  attr_reader :tipo, :peso, :volume

  @@valori = Hash.new(1)  # variabile statica che assegna i valori
                          # ai tipi di articolo

  # costruttore: initialize(String t, int p, int v)
  # crea un nuovo articolo di tipo t, peso p e volume v
  def initialize(t,p,v)
    @tipo = t
    @peso = p
    @volume = v
  end

  def ==(b)
    if b.is_a?(Articolo)
      @tipo==b.tipo && @peso==b.peso && @volume==b.volume
    else
      false
    end
  end

  def to_s
    "<#@tipo> peso: #@peso volume: #@volume"
  end

  # int hash() e boolean eql?()
  # definiamo queste due fuzioni per gli oggetti della classe Articolo
  # in modo che possano essere usati come chiavi di un Hash
  def hash
     @tipo.hash + 11*(@peso.hash + 13*(@volume.hash + 19))
  end
  def eql?(b)
    self==b
  end

  # int valore()
  # restituisce il valore attualmente associato all'oggetto self
  def valore()
    @@valori[@tipo]
  end

  # metodo di classe: void assegna_valore(String t, int val)
  # assegna il valore val a tutti gli Articoli di tipo t
  def Articolo.assegna_valore(t,val)
    @@valori[t] = val
  end

end

class Magazzino

  def initialize()
    @magazzino={}
  end

  def aggiungi_scorte(a,q)
    @magazzino[a]+=q
    return magazzino[a]
  end

  def prendi1(a)
    unless @magazzino.has_key?(a)
      raise ArtNonDispException
    else
    @magazzino[a]-=1
    return @magazzino[a]
  end
  end
  def disponibile?(a)
    return true if @magazzino[a] >= 1
    return false
  end

  def disponibili()
    return @magazzino.find_all{|x| x >= 1}
  end

  def volume_tot()
    tot=0
    @magazzino.each{|x| tot+=x.volume}
    return tot
  end
   def to_s()
     s="contenuto magazzino  \n"
     @magazzino.each{|i| s+="#{@magazzino[i]}: quantità #{i}"}
     return s
   end


end


def main

  m = Magazzino.new()

  puts "--------- riempiamo il magazzino ------------"
  t1 = Articolo.new("tenda",10,8)# primo tipo di tenda
  m.aggiungi_scorte(t1,2)
  puts m.disponibile?(Articolo.new("tenda",10,9)) #f
  puts m.disponibile?(Articolo.new("tenda",10,8)) #t

  m.aggiungi_scorte(Articolo.new("tenda",15,9),5) # secondo tipo di tenda

  m.prendi1(t1)
  m.prendi1(t1)
  puts m.disponibile?(t1) # f
  begin
   m.prendi1(t1)
  rescue ArtNonDispException => e
    puts "L'articolo #{t1} non e' disponibile"
  end
  m.aggiungi_scorte(t1,3)
  m.aggiungi_scorte(Articolo.new("tenda",20,10),3)
  m.aggiungi_scorte(Articolo.new("bussola",1,1),7)
  m.aggiungi_scorte(Articolo.new("radio",2,1),5)
  m.aggiungi_scorte(Articolo.new("radio",3,2),2)
  m.aggiungi_scorte(Articolo.new("torcia",1,2),5)
  m.aggiungi_scorte(Articolo.new("torcia",5,3),3)
  m.aggiungi_scorte(Articolo.new("radio",3,2),4)  # radio gia' esistente
  m.aggiungi_scorte(Articolo.new("sacco a pelo",1,3),5)
  m.aggiungi_scorte(Articolo.new("fornello",4,3),3)
  m.aggiungi_scorte(Articolo.new("set pentole",15,8),3)
  m.aggiungi_scorte(Articolo.new("siero antivipera",1,1),0)
  m.aggiungi_scorte(Articolo.new("spazzolino",1,1),30)
  m.aggiungi_scorte(Articolo.new("notebook",5,2),1)
  m.aggiungi_scorte(Articolo.new("notebook",8,2),1)
  m.aggiungi_scorte(Articolo.new("borraccia",2,1),4)
  m.aggiungi_scorte(Articolo.new("borraccia",10,5),4)
  m.aggiungi_scorte(Articolo.new("paracadute",10,50),3)
  ms = Articolo.new("motosega",50,10)
  m.aggiungi_scorte(ms,1)

  puts m
  puts "Il magazzino contiene #{m.disponibili.size} articoli differenti"
  puts "Il volume totale occupato e' #{m.volume_tot}"

  puts "------- creiamo 2 zaini -------"
  zpiccolo = Zaino.new(80,60)
  zgrande  = Zaino.new(200,120)

  puts zpiccolo.puo_contenere?(Articolo.new("motoscafo",2000,1000)) # f
  puts zpiccolo.puo_contenere?(ms) # t
  puts zpiccolo.aggiungi(ms) #t
  puts zpiccolo.puo_contenere?(ms) # f
  puts zpiccolo.aggiungi(ms) #f
  puts zpiccolo.aggiungi(Articolo.new("torcia",5,2)) #t
  puts zpiccolo.aggiungi(Articolo.new("torcia",5,2)) #t
  puts zpiccolo.aggiungi(Articolo.new("canna da pesca",4,3)) #t
  puts zpiccolo.aggiungi(Articolo.new("fornello",6,4)) #t
  puts zpiccolo.aggiungi(Articolo.new("tenda",11,14)) #f


  puts zpiccolo
  puts zpiccolo.contiene_tipo?("bussola") #f
  puts zpiccolo.contiene_tipo?("mappa") #f
  puts zpiccolo.contiene_tipo?("fornello") #t


  puts " ------ assegnamo valori ai tipi di articoli ------"
  Articolo.assegna_valore("radio",4)
  Articolo.assegna_valore("tenda",10)
  Articolo.assegna_valore("bussola",10)
  Articolo.assegna_valore("fornello",8)
  Articolo.assegna_valore("fornello",5) # conta l'ultimo valore messo!
  Articolo.assegna_valore("torcia",4)
  Articolo.assegna_valore("spazzolino",4)
  Articolo.assegna_valore("notebook",12)
  Articolo.assegna_valore("spada laser",15)

  puts zpiccolo
  zpiccolo.svuota
  puts zpiccolo
  puts zpiccolo.contiene_tipo?("bussola") #f
  puts zpiccolo.contiene_tipo?("mappa") #f
  puts zpiccolo.contiene_tipo?("fornello") #f


  puts "------- prove di riempimento --------"

  zpiccolo.riempi(m)
  puts zpiccolo
  #puts m
  zgrande.riempi(m)
  puts zgrande

  puts "-------- fine test ----------"
  return nil

end

main